﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace ZackFlame.SimpleBrainFuck.Core.Statments
{
    public abstract class Statment
    {
        public int Line { get; set; }
    }

    public class BrainIf : Statment
    {
        public BrainArg Parameter { get; set; }

        public LinkedList<Statment> IfStatments { get; set; }

        public LinkedList<Statment> ElseStatments { get; set; }

        public BrainIf()
        {
            IfStatments = new LinkedList<Statment>();
            ElseStatments = new LinkedList<Statment>();
        }

        public override string ToString()
        {
            return string.Format("if {0}", 
                Parameter != null ? Parameter.ToString() : "???");
        }
    }

    public class BrainDef : Statment
    {
        internal static readonly Regex NameRegex = new Regex("^[a-zA-Z_]+[a-zA-Z_0-9]*$");

        private string name;
        private Func<string[], string> renderer;

        public string Name
        {
            get { return name; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException();

                name = value;
            }
        }

        public List<BrainMacros> MacrosArgs { get; set; }

        public LinkedList<Statment> Statments { get; set; }

        public bool CanRenderItself
        {
            get { return renderer != null; }
        }

        public BrainDef(Func<string[], string> renderer)
            : this()
        {
            this.renderer = renderer;
        }

        public BrainDef()
        {
            MacrosArgs = new List<BrainMacros>();
            Statments = new LinkedList<Statment>();
        }

        public string Render(string[] parameters)
        {
            if (renderer == null)
                throw new NotSupportedException();

            return renderer(parameters);
        }

        public override string ToString()
        {
            return string.Format(
                "def {0} ({1} params)",
                Name,
                MacrosArgs != null ? MacrosArgs.Count.ToString() : "???");
        }
    }


    public class BrainCall : Statment
    {
        private string defName = string.Empty;

        public string DefName
        {
            get { return defName; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException();

                defName = value;
            }
        }

        public List<BrainArg> CallArgs { get; private set; }

        public BrainCall()
        {
            CallArgs = new List<BrainArg>();
        }

        public override string ToString()
        {
            return string.Format("${0} ({1} args)", DefName, CallArgs.Count);
        }
    }

    public class BrainArg : Statment
    {
        private string value = string.Empty;

        public string Value
        {
            get { return this.value; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException();

                this.value = value;
            }
        }

        public override string ToString()
        {
            return string.Format("\"{0}\"", value);
        }
    }

    public class BrainMacros : BrainArg
    {
        internal static readonly Regex NameRegex = new Regex("^(-)?([a-zA-Z_]+[a-zA-Z_~0-9]*)$");

        private string name;

        public string Name
        {
            get { return name; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException();

                name = value;
            }
        }

        public bool Negative { get; set; }

        public BrainMacros()
            : this(string.Empty)
        {
        }

        public BrainMacros(string name)
        {
            this.name = name;
        }

        public override string ToString()
        {
            return string.Format("@{0}", Name);
        }
    }

    public class BrainMacrosAssignment : BrainMacros
    {
        public BrainMacrosExpression Expression { get; set; }

        public BrainMacrosAssignment()
            : base()
        {
        }

        public BrainMacrosAssignment(string name)
            : base(name)
        {
        }

        public override string ToString()
        {
            return string.Format(
                "@{0} = {1}",
                Name,
                Expression != null ? Expression.ToString() : "???");
        }
    }

    public class BrainMacrosExpression
    {
        public BrainArg Left { get; set; }

        public BrainArg Right { get; set; }

        public string Operator { get; set; }

        public override string ToString()
        {
            return string.Format(
                "{0} {1}{2}",
                Left,
                Operator ?? "???",
                Right != null ? " " + Right.ToString() : string.Empty);
        }
    }

    public class BrainPureCode : Statment
    {
        private string value = string.Empty;

        public string Value
        {
            get { return value; }
            set
            {
                if (value == null)
                    throw new ArgumentNullException();

                this.value = value;
            }
        }

        public override string ToString()
        {
            return value;
        }
    }
}
